package com.kd.url.dictionary;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import com.kd.crawler.common.utils.PropertiesUtils;
import com.kd.crawler.common.utils.StringUtils;
import com.kd.crawler.dao.crawler.CrawlerEntryDao;
import com.kd.crawler.entity.CrawlerEntry;

public class EntryUrlDictionary {
	
	private Properties pro = null;
	private boolean allowOpenInside = false;
	private boolean allowOpenOutside = false;
	
	private static Set<String> entryUrlInsideDic;
	private static Set<String> entryUrlOutsideDic;
	
	private static volatile boolean isLoaded = false;
	
	private static final EntryUrlDictionary eud = new EntryUrlDictionary();

	private EntryUrlDictionary() {
		pro = PropertiesUtils.getProperties("entryUrls.properties");
		allowOpenInside = Boolean.parseBoolean(pro.getProperty("allowedOpenInside", "false"));
		allowOpenOutside = Boolean.parseBoolean(pro.getProperty("allowedOpenOutside", "false"));
	}
	
	public static EntryUrlDictionary getInstance() {
		return eud;
	}
	
	public synchronized void init() {
		if(isLoaded) {
			return ;
		}
		if(allowOpenInside) {
			// load default inside entry urls
			String fileName = pro.getProperty("insideEntryUrlDic", "entryUrls_inside.dic");
			entryUrlInsideDic = load(fileName);
			// load extend inside entry urls
			String extFileName = pro.getProperty("ext_insideDic", "");
			if(StringUtils.isNotBlank(extFileName)) {
				entryUrlInsideDic.addAll(loadExtendDic(extFileName));
			}
		}
		
		if(allowOpenOutside) {
			// load default outside entry urls
			String fileName = pro.getProperty("outsideEntryUrlDic", "entryUrls_outside.dic");
			entryUrlOutsideDic = load(fileName);
			// load extend outside entry urls
			String extFileName = pro.getProperty("ext_outsideDic", "");
			if(StringUtils.isNotBlank(extFileName)) {
				entryUrlOutsideDic.addAll(loadExtendDic(extFileName));
			}
		}
		isLoaded = true;
	}
	
	public Set<String> load(String fileName) {
		Set<String> entryUrls = new HashSet<String>();
		ClassLoader cl = EntryUrlDictionary.class.getClassLoader();
		if(null == cl) {
			return entryUrls;
		}
		BufferedReader br = null;
		br = new BufferedReader(new InputStreamReader(cl.getResourceAsStream(fileName)));
		String url = null;
		try {
			while((url=br.readLine()) != null) {
				entryUrls.add(url);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(null != br) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return entryUrls;
	}
	
	public Set<String> loadExtendDic(String extFileNameStr) {
		Set<String> extEntryUrlDics = new HashSet<String>();
		String[] extFileNames = extFileNameStr.split(";");
		for(String extFileName : extFileNames) {
			if(StringUtils.isBlank(extFileName)) {
				continue;
			}
			Set<String> extEntryUrlDic = load(extFileName);
			extEntryUrlDics.addAll(extEntryUrlDic);
		}
		return extEntryUrlDics;
	}
	
	/**
	 * if true, the entry url set contains the entry url, it says that the url is undetailed url.
	 * but sometimes, return false, the entry url maybe a entry url, or a detailed url.
	 * so, this method can judge the url must be a entry url when return true.
	 * @param url
	 * @return
	 */
	public boolean find(String url, boolean isInside) {
		if(StringUtils.isBlank(url)) {
			return false;
		}
		init();
		if(isInside) {
			if(entryUrlInsideDic.contains(url)) {
				return true;
			}
		} else {
			if(entryUrlOutsideDic.contains(url)) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * reload entry urls from database, when the related database updated or add some new entry urls.
	 */
	public void refresh() {
		if(allowOpenInside) {
			String fileName = pro.getProperty("insideEntryUrlDic", "entryUrls_inside.dic");
			refresh(fileName, true);
		}
		if(allowOpenOutside) {
			String fileName = pro.getProperty("outsideEntryUrlDic", "entryUrls_outside.dic");
			refresh(fileName, false);
		}
			
	}
	public void refresh(String fileName, boolean isInside) {
		int start = 0;
		PrintWriter writer = null;
		try {
			String path = EntryUrlDictionary.class.getClassLoader().getResource(fileName).getPath();
			writer = new PrintWriter(new FileOutputStream(new File(path)), true);
			while(true) {
				List<CrawlerEntry> ces = null;
				if(isInside) {
					ces = CrawlerEntryDao.getInstance().queryInside(start, 1000);
				} else {
					ces = CrawlerEntryDao.getInstance().queryOutside(start, 100);
				}
				if(null==ces || 0==ces.size()) {
					break;
				}
				for(CrawlerEntry ce : ces) {
					writer.println(ce.getUrl());
				}
				start = ces.get(ces.size()-1).getEntryId();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(null != writer) {
				writer.close();
			}
		}
	}
	
	public static void main(String[] args) {
//		EntryUrlDictionary.getInstance().refresh();
		String url = "http://www.163.coms/";
		System.out.println(EntryUrlDictionary.getInstance().find(url, true));
	}
}
